package com.zb.store.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zb.entity.*;
import com.zb.result.PageUtil;
import com.zb.service.*;
import com.zb.store.service.ConStoreService;
import com.zb.view.*;
import com.zb.vo.StoreDetailGoodsListVo;
import com.zb.vo.StoreListVo;
import com.zb.vo.StoreSelectVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author WEN
 * @Date 2023/10/31 0031
 **/
@Service
public class ConStoreServiceImpl implements ConStoreService {
    @Resource
    private ZjStoreService storeService;
    @Resource
    private ZjWorkSpareMaterialService workSpareMaterialService;
    @Resource
    private ZjWorkSpareReturnService workSpareReturnService;
    @Resource
    private ZjStoreThirdService storeThirdService;
    @Resource
    private ZjStoreGoodsStockService storeGoodsStockService;
    @Resource
    private ViewGoodsService viewGoodsService;
    @Resource
    private ZjStoreGoodsStockCodeService storeGoodsStockCodeService;
    @Resource
    private ZjStoreInboundMaterialService storeInboundMaterialService;
    @Resource
    private ZjStoreOutboundMaterialService storeOutboundMaterialService;
    @Resource
    private ZjNetworkService networkService;
    @Resource
    private ViewNetworkEmpAccountService viewNetworkEmpAccountService;


    // 批量启用或禁用仓库
    @Override
    public void updateDisabledBatchById(List<Long> ids, boolean status) {
        if (CollectionUtil.isEmpty(ids)) {
            return;
        }
        if (status) {
            // 关联工单
            List<Long> storeIds = workSpareMaterialService.getRelationByStoreIds(ids);
            StoreExceptionMessage(storeIds, "服务工单配件关联，不可禁用");
            storeIds = workSpareReturnService.getRelationByStoreIds(ids);
            StoreExceptionMessage(storeIds, "服务工单备件旧件退回关联，不可禁用仓库");
            // 入库物料
            storeIds = storeInboundMaterialService.getByStoreIds(ids);
            StoreExceptionMessage(storeIds, "入库物料关联，不可禁用");
            // 出库物料
            storeIds = storeOutboundMaterialService.getByStoreIds(ids);
            StoreExceptionMessage(storeIds, "出库物料关联，不可禁用");
            // 查询库存一物一码，是否存在已出入库的库存物料关联仓库
            storeIds = storeGoodsStockCodeService.getStoreIdByDelStoreIds(ids);
            StoreExceptionMessage(storeIds, "仓库库存关联，不可禁用");
        }
        storeService.updateDisabledBatchById(ids, status);
    }

    // 批量删除仓库
    @Override
    public void deleteBatchById(List<Long> ids) {
        // 关联工单
        List<Long> storeIds = workSpareMaterialService.getRelationByStoreIds(ids);
        StoreExceptionMessage(storeIds, "服务工单配件关联，不可删除");
        storeIds = workSpareReturnService.getRelationByStoreIds(ids);
        StoreExceptionMessage(storeIds, "服务工单备件旧件退回关联，不可删除");
        // 入库物料
        storeIds = storeInboundMaterialService.getByStoreIds(ids);
        StoreExceptionMessage(storeIds, "入库物料关联，不可删除");
        // 出库物料
        storeIds = storeOutboundMaterialService.getByStoreIds(ids);
        StoreExceptionMessage(storeIds, "出库物料关联，不可删除");
        // 查询库存一物一码，是否存在已出入库的库存物料关联仓库
        storeIds = storeGoodsStockCodeService.getStoreIdByDelStoreIds(ids);
        StoreExceptionMessage(storeIds, "仓库库存关联，不可删除");
        storeGoodsStockService.deleteBatchByStoreId(ids);
        storeThirdService.removeByIds(ids);
        storeService.removeByIds(ids);
    }

    private void StoreExceptionMessage(List<Long> ids, String message) {
        if (CollectionUtil.isEmpty(ids)) {
            return;
        }
        QueryWrapper<ZjStore> wrapper = new QueryWrapper<>();
        wrapper.select("name");
        wrapper.in("id", ids);
        String names = storeService.list(wrapper).stream().map(ZjStore::getName).collect(Collectors.joining("、"));
        Assert.isTrue(false, "仓库名称[ "+ names +" ]已与"+ message);
    }

    // 根据仓库ID获取仓库库存明细
    @Override
    public Map<String, Object> getStoreDetailGoodsList(Long storeId, PageUtil pageUtil) {
        PageUtil.setPageLimit(pageUtil);
        QueryWrapper<ZjStoreGoodsStock> storeGoodsStockQueryWrapper =  new QueryWrapper<>();
        storeGoodsStockQueryWrapper.select("id", "store_id", "goods_type", "goods_id", "goods_spec_id", "system_stock")
                .eq("store_id", storeId);
        Page<ZjStoreGoodsStock> page = storeGoodsStockService.page(new Page<>(pageUtil.getPage(), pageUtil.getLimit()), storeGoodsStockQueryWrapper);
        return PageUtil.pageList(page.getCurrent(), page.getSize(), page.getTotal(), getStoreDetailGoods(storeId, null, page.getRecords()));

//        List<ViewStoreGoodsStockGoods> goodsStockGoodsList = viewStoreGoodsStockGoodsService.getStoreDetailGoodsList(storeId, pageUtil);
//        return PageUtil.pageList(pageUtil.getPage(), pageUtil.getLimit(), viewStoreGoodsStockGoodsService.getStoreDetailGoodsListCount(storeId), getStoreDetailGoods(storeId, null, goodsStockGoodsList));
    }

    // 根据仓位ID获取仓位库存明细
    @Override
    public Map<String, Object> getStorePositionDetailGoodsList(Long storePositionId, PageUtil pageUtil) {
        PageUtil.setPageLimit(pageUtil);
        QueryWrapper<ZjStoreGoodsStock> storeGoodsStockQueryWrapper =  new QueryWrapper<>();
        storeGoodsStockQueryWrapper.select("id", "store_position_id", "goods_type", "goods_id", "goods_spec_id", "system_stock")
                .eq("store_position_id", storePositionId);
        Page<ZjStoreGoodsStock> page = storeGoodsStockService.page(new Page<>(pageUtil.getPage(), pageUtil.getLimit()), storeGoodsStockQueryWrapper);
        return PageUtil.pageList(page.getCurrent(), page.getSize(), page.getTotal(), getStoreDetailGoods(null, storePositionId, page.getRecords()));
    }

    /**
     * 获取仓库详情仓库库存明细
     * @param goodsStockList
     */
    private List<StoreDetailGoodsListVo> getStoreDetailGoods(Long storeId, Long storePositionId, List<ZjStoreGoodsStock> goodsStockList) {
        List<Long> goodsIds = goodsStockList.stream().map(ZjStoreGoodsStock::getGoodsId).distinct().toList();
        List<Long> goodsSpecIds = goodsStockList.stream().map(ZjStoreGoodsStock::getGoodsSpecId).distinct().toList();
        List<ViewGoods> viewGoodsList = viewGoodsService.getByGoodsIdsAndGoodsSpecIds(goodsIds, goodsSpecIds);
        List<ZjStoreInboundMaterial> inboundMaterials = storeInboundMaterialService.getInStoreQtyByStoreIdOrStorePositionIdAndGroupByGoodsId(storeId, storePositionId, goodsIds, goodsSpecIds);
        List<ZjStoreOutboundMaterial> outboundMaterials = storeOutboundMaterialService.getOutStoreQtyByStoreIdOrStorePositionIdAndGroupByGoodsId(storeId, storePositionId, goodsIds, goodsSpecIds);
        List<StoreDetailGoodsListVo> voList = goodsStockList.stream().map(goodsStock -> {
            StoreDetailGoodsListVo vo = new StoreDetailGoodsListVo();
            vo.setType(goodsStock.getGoodsType());
            vo.setSystemStock(goodsStock.getSystemStock());
            vo.setAvailableStock(new BigDecimal(vo.getSystemStock() +"")
                    .add(new BigDecimal(inboundMaterials.stream().filter(f -> Objects.equals(f.getGoodsId(), goodsStock.getGoodsId())
                            && Objects.equals(f.getGoodsSpecId(), goodsStock.getGoodsSpecId())).map(ZjStoreInboundMaterial::getQty).findFirst().orElse(0L).toString()))
                    .subtract(new BigDecimal(outboundMaterials.stream().filter(f -> Objects.equals(f.getGoodsId(), goodsStock.getGoodsId())
                            && Objects.equals(f.getGoodsSpecId(), goodsStock.getGoodsSpecId())).map(ZjStoreOutboundMaterial::getQty).findFirst().orElse(0L).toString()))
                    .longValue()
            );
            viewGoodsList.stream().filter(f -> Objects.equals(f.getGoodsType(), goodsStock.getGoodsType()) && Objects.equals(f.getId(), goodsStock.getGoodsId())
                    && Objects.equals(f.getSpecId(), goodsStock.getGoodsSpecId())).findFirst().ifPresent(goods -> {
                vo.setGoodsBrand(goods.getBrand());
                vo.setGoodsType(goods.getType());
                vo.setGoodsName(goods.getName());
                vo.setGoodsModel(goods.getModel());
                vo.setGoodsSpecName(goods.getSpecName());
                vo.setGoodsUnit(goods.getUnit());
            });
            return vo;
        }).toList();
        return voList;
    }

    // 获取仓库列表
    @Override
    public Map<String, Object> getList(Long custAccId, StoreSelectVo selectVo) {
        PageUtil.setPageLimit(selectVo);
        List<ZjStore> storeList = storeService.getList(custAccId, selectVo);
        List<Long> networkIds = storeList.stream().filter(f -> f.getOutStore() && f.getOutStoreType() == 1).map(ZjStore::getRelationId).distinct().toList();
        List<Long> networkEmpIds = storeList.stream().filter(f -> f.getOutStore() && f.getOutStoreType() == 2).map(ZjStore::getRelationId).distinct().toList();
        List<ZjNetwork> networkList =  networkService.getNameByIds(networkIds);
        List<ViewNetworkEmpAccount> empDetailList = viewNetworkEmpAccountService.getByIds(networkEmpIds);
        List<StoreListVo> voList = storeList.stream().map(store -> {
            StoreListVo vo = new StoreListVo();
            BeanUtil.copyProperties(store, vo);
            vo.setStatus(store.getDisabled());
            vo.setStoreNo(store.getCode());
            vo.setCreateTime(store.getGmtCreate());
            vo.setUpdateTime(store.getGmtUpdate());
            if (store.getOutStore()) {
                if (store.getOutStoreType() == 1) networkList.stream().filter(f -> Objects.equals(f.getId(), store.getRelationId())).map(ZjNetwork::getName).findFirst().ifPresent(vo::setRelateionName);
                if (store.getOutStoreType() == 2) empDetailList.stream().filter(f -> Objects.equals(f.getId(), store.getRelationId())).map(ViewNetworkEmpAccount::getName).findFirst().ifPresent(vo::setRelateionName);
            }
            return vo;
        }).toList();
        return PageUtil.pageList(selectVo.getPage(), selectVo.getLimit(), storeService.getListCount(custAccId, selectVo), voList);
    }



    // 仓库下拉列表查询
    @Override
    public Map<String, Object> storePageSelect(Long custAccId, String storeType, SelectVo selectVo) {
        PageUtil.setSelectPageLimit(selectVo);
        QueryWrapper<ZjStore> wrapper = new QueryWrapper<>();
        wrapper.select("id", "name", "is_enable_store_position AS enableStorePosition", "is_out_store AS outStore", "out_store_type", "relation_id");
        wrapper.eq("cust_acc_id", custAccId).eq("is_disabled", false);
        if (Objects.equals("0", storeType)) {
            wrapper.eq("is_out_store", false);
        } else {
            wrapper.eq("is_out_store", true);
            wrapper.eq("out_store_type", storeType);
        }
        if (StringUtils.isNotBlank(selectVo.getName())) {
            wrapper.like("name", selectVo.getName());
        }
        Page<ZjStore> page = storeService.page(new Page<>(selectVo.getPage(), selectVo.getLimit()), wrapper);
        List<Long> networkIds = page.getRecords().stream().filter(f -> f.getOutStore() && f.getOutStoreType() == 1).map(ZjStore::getRelationId).distinct().toList();
        List<Long> networkEmpIds = page.getRecords().stream().filter(f -> f.getOutStore() && f.getOutStoreType() == 2).map(ZjStore::getRelationId).distinct().toList();
        List<ZjNetwork> networkList =  networkService.getNameByIds(networkIds);
        List<ViewNetworkEmpAccount> empDetailList = viewNetworkEmpAccountService.getByIds(networkEmpIds);
        List<SelectStoreVo> voList = page.getRecords().stream().map(s -> {
            return new SelectStoreVo(s.getId(), getStoreRelation(s, networkList, empDetailList), s.getEnableStorePosition());
        }).toList();
        return PageUtil.pageList(page.getCurrent(), page.getSize(), page.getTotal(), voList);
    }

    // 仓库人员地址下拉列表查询
    @Override
    public Map<String, Object> storeEmpAddressPageSelect(Long custAccId, String storeType, SelectVo selectVo) {
        PageUtil.setSelectPageLimit(selectVo);
        QueryWrapper<ZjStore> wrapper = new QueryWrapper<>();
        wrapper.select("id", "name", "is_enable_store_position AS enableStorePosition", "user_name", "user_phone", "province", "city", "area", "town", "address", "is_out_store AS outStore", "out_store_type", "relation_id");
        wrapper.eq("cust_acc_id", custAccId).eq("is_disabled", false);
        if (Objects.equals("0", storeType)) {
            wrapper.eq("is_out_store", false);
        } else {
            wrapper.eq("is_out_store", true);
            wrapper.eq("out_store_type", storeType);
        }
        if (StringUtils.isNotBlank(selectVo.getName())) {
            wrapper.like("name", selectVo.getName());
        }
        Page<ZjStore> page = storeService.page(new Page<>(selectVo.getPage(), selectVo.getLimit()), wrapper);
        List<Long> networkIds = page.getRecords().stream().filter(f -> f.getOutStore() && f.getOutStoreType() == 1).map(ZjStore::getRelationId).distinct().toList();
        List<Long> networkEmpIds = page.getRecords().stream().filter(f -> f.getOutStore() && f.getOutStoreType() == 2).map(ZjStore::getRelationId).distinct().toList();
        List<ZjNetwork> networkList =  networkService.getNameByIds(networkIds);
        List<ViewNetworkEmpAccount> empDetailList = viewNetworkEmpAccountService.getByIds(networkEmpIds);
        List<SelectStoreEmpAddressVo> voList = page.getRecords().stream().map(s -> {
            SelectStoreEmpAddressVo vo = new SelectStoreEmpAddressVo();
            vo.setId(s.getId());
            vo.setName(getStoreRelation(s, networkList, empDetailList));
            vo.setEnableStorePosition(s.getEnableStorePosition());
            vo.setUserName(s.getUserName());
            vo.setPhone(s.getUserPhone());
            vo.setProvince(s.getProvince());
            vo.setCity(s.getCity());
            vo.setArea(s.getArea());
            vo.setTown(s.getTown());
            vo.setAddress(s.getAddress());
            return vo;
        }).toList();
        return PageUtil.pageList(page.getCurrent(), page.getSize(), page.getTotal(), voList);
    }

    private String getStoreRelation(ZjStore store, List<ZjNetwork> networkList, List<ViewNetworkEmpAccount> empDetailList) {
        String name = store.getName();
        if (store.getOutStore()) {
            if (store.getOutStoreType() == 1) {
                return "【" +networkList.stream().filter(f -> Objects.equals(f.getId(), store.getRelationId())).map(ZjNetwork::getName).findFirst().get()+"】" + name;
            }
            return "【" +empDetailList.stream().filter(f -> Objects.equals(f.getId(), store.getRelationId())).map(ViewNetworkEmpAccount::getName).findFirst().get()+"】" + name;
        }
        return name;
    }
}
